# coding=utf-8
from __future__ import print_function, absolute_import

import operator
from datetime import timedelta

import akshare as ak
import talib as ta
from gm.api import *


# 策略中必须有init方法
def init(context):
    # 选股
    schedule(schedule_func=algo_select, date_rule='1d', time_rule='11:27:00')

    # 首单
    schedule(schedule_func=trade_stocks, date_rule='1d', time_rule='13:01:00')

    # 加仓单
    # schedule(schedule_func=add_trade_stocks, date_rule='1d', time_rule='09:34:00')

    # 通过get_instruments获取所有的上市股票代码
    context.all_stock = get_instruments(exchanges='SHSE, SZSE', sec_types=[1], skip_suspended=False,
                                        skip_st=False, fields='symbol, listed_date, delisted_date',
                                        df=True)

    # algo_select(context)
    # 建仓股票池
    context.trade_stocks = []


def algo_select(context):
    # a股破净率数据
    context.stock_a_below_net_asset_statistics_df = ak.stock_a_below_net_asset_statistics(symbol="全部A股")

    print("当前持仓股数量", len(context.account().positions()))
    date_net = context.now.strftime("%Y-%m-%d")
    # 市场分析
    """
        只在市场破净率大于1%时执行选股

    market_value = context.stock_a_below_net_asset_statistics_df[
        (context.stock_a_below_net_asset_statistics_df['date'] == date_net) & (
                context.stock_a_below_net_asset_statistics_df['below_net_asset_ratio'] >= 0.01)]
    if len(market_value) == 0:
        return
    """

    # 获取筛选时间：date1表示当前日期之前的100天，date2表示当前时间
    date1 = (context.now - timedelta(days=100)).strftime("%Y-%m-%d %H:%M:%S")
    date2 = context.now.strftime("%Y-%m-%d %H:%M:%S")

    # 上市不足100日的新股和退市股和B股
    code = context.all_stock[
        (context.all_stock['listed_date'] < date1) & (context.all_stock['delisted_date'] > date2) & (
                context.all_stock['symbol'].str[5] != '9') & (context.all_stock['symbol'].str[5] != '2')]

    # 剔除停牌
    df_code = get_history_instruments(symbols=code['symbol'].to_list(), start_date=date2, end_date=date2, df=True)
    df_code = df_code[(df_code['is_suspended'] == 0) & (df_code['sec_level'] == 1)]

    stock_zh_a_spot_em_df = ak.stock_zh_a_spot_em()
    stocks_values = stock_zh_a_spot_em_df[
        (stock_zh_a_spot_em_df['市净率'] <= 1) & (stock_zh_a_spot_em_df['市净率'] > 0) & (
                stock_zh_a_spot_em_df['市盈率-动态'] > 0)]

    # 个股分析
    print("市净率大于0小于1，同时市盈率动态大于0的股票数量为", len(stocks_values), date_net)
    if len(stocks_values) == 0:
        print("没有满足条件的股票")
        return

    for symbol in stocks_values['代码']:
        print("二次判断，", symbol)
        can_trade = False

        tmp_symbol = symbol

        symbol = contains_code(symbol, df_code['symbol'])

        if symbol is None:
            continue

        history_n_data = history_n(symbol=symbol, frequency='1d', count=10000000, end_time=context.now,
                                   fields='symbol, open, close, high', adjust=ADJUST_PREV, df=True)
        print(symbol, "获取历史值完毕")
        if len(history_n_data) < 3:
            print(symbol, "历史值小于3不符合条件")
            continue

        last_close = history_n_data['close'].loc[len(history_n_data) - 1]

        highest = history_n_data['high'].max()

        if last_close >= highest:
            print(symbol, "昨日收盘价大于历史最高价不符合条件")
            continue

        '''
                高估价区域
            '''
        sma = ta.MA(history_n_data['close'], len(history_n_data), 0)
        mid_high = highest / 2

        if last_close >= sma[len(history_n_data) - 1] or last_close >= mid_high:
            print(symbol, "昨日收盘价在高估价区域不符合条件")
            continue

        '''
                合理估价区域
            '''
        normal_high = mid_high / 2
        normal_ma = sma[len(history_n_data) - 1] / 2

        if last_close >= normal_high or last_close >= normal_ma:
            print(symbol, "不在合理估价区域不符合条件")
            continue
        if last_close <= normal_high and last_close <= normal_ma:
            can_trade = True
            print(symbol, "在合理估价区域满足条件")

        '''
                低估价区域
            
            low_high = mid_high * 0.2
            low_sma = sma[len(history_n_data) - 1] * 0.2
            if last_close < low_sma or last_close < low_high:
                print("")
            '''
        '''
                绝对低估价区域
            
            lowest_ma = normal_ma * 0.2
            lowest_high = normal_high * 0.2
            '''
        if can_trade:
            print("判断", tmp_symbol, "是否有大资金买入")
            stock_individual_fund_flow_df = ak.stock_individual_fund_flow(stock=tmp_symbol,
                                                                          market=code_market(str(tmp_symbol)))
            if len(stock_individual_fund_flow_df) > 0:
                fund_flow = stock_individual_fund_flow_df.iloc[-1]
                if is_number(fund_flow['超大单净流入-净额']) and float(fund_flow['超大单净流入-净额']) > 0:
                    print(tmp_symbol, "昨日有大资金买入", "资金额度为", fund_flow['超大单净流入-净额'])
                    can_trade = True
                else:
                    print(tmp_symbol, "昨日无大资金买入")
                    can_trade = False

        if can_trade:
            # 指定持仓
            account_position = context.account().position(symbol=symbol, side=PositionSide_Long)
            if account_position is None:
                context.trade_stocks.append(symbol)
                print(symbol, "满足建仓条件,已加入股票池")
            else:
                print(symbol, "该股票已经有持仓不再放入股票池")
    print("交易股票池构建完成,数量为", len(context.trade_stocks))


def take_profit(context):
    cash = context.account().cash
    npl_percent = 0
    if cash.market_value != 0:
        npl_percent = cash.fpnl / (cash.market_value - cash.fpnl) * 100
    if npl_percent >= 20:
        order_close_all()
        print('帐户浮盈大于20%全部平仓')

    # 所有持仓
    account_positions = context.account().positions()
    if len(account_positions) != 0:
        for position in account_positions:
            fpnl_percent = position.fpnl / (position.amount - position.fpnl) * 100
            if fpnl_percent >= 20 or fpnl_percent <= -10:
                order_target_percent(symbol=position.symbol, percent=0, order_type=OrderType_Market,
                                     position_side=PositionSide_Long)
                print('平仓', position.symbol)


def add_trade_stocks(context):
    return


def trade_stocks(context):
    take_profit(context)
    print(len(context.trade_stocks), "执行交易的股票数量")
    if len(context.trade_stocks) == 0:
        return
    for symbol in context.trade_stocks:
        # 指定持仓
        account_position = context.account().position(symbol=symbol, side=PositionSide_Long)
        if account_position is None:
            print(symbol, "开始建仓")
            order = order_target_percent(symbol=symbol, percent=0.05, order_type=OrderType_Market,
                                         position_side=PositionSide_Long)
            if len(order) != 0:
                print(symbol, "已经完成建仓，将从建仓股票池剔除该股票")
                context.trade_stocks.remove(symbol)
        else:
            context.trade_stocks.remove(symbol)


def contains_code(code, symbols):
    symbol_final = None
    for symbol in symbols:
        if operator.contains(symbol, code):
            symbol_final = symbol
    return symbol_final


def code_market(code):
    if code.startswith('00') or code.startswith('30'):
        code = 'sz'
    if code.startswith('6'):
        code = 'sh'
    return code


def is_number(s):
    try:
        f = float(s)
        if f != f or f == float('inf') or f == float('-inf'):
            return False
        return True
    except ValueError:
        return False


def on_error(context, code, info):
    print('code:{}, info:{}'.format(code, info))
    stop()
